package com.icode.web.startup.security.access;

import com.icode.core.model.ProtectedURLs;
import com.icode.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * User: alexz
 * Date: 2015/9/30
 * Time: 14:11
 */
public class DynamicWebExpressionVoter extends WebExpressionVoter {

    @Autowired
    private UserService userService;

    @Override
    public int vote(Authentication authentication, FilterInvocation fi, Collection<ConfigAttribute> attributes) {
        if (authentication instanceof AnonymousAuthenticationToken) {
            return super.vote(authentication, fi, attributes);
        }

        List<ProtectedURLs> protectedURLs = userService.loadProtectedURLs();
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (ProtectedURLs protectedURL : protectedURLs) {
            Set<String> urls = protectedURL.getUrl();
            for (String url : urls) {
                String method = protectedURL.getMethod();
                AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(url, method);
                if (antPathRequestMatcher.matches(fi.getRequest())) {
                    Set<String> protectedAuthorities = protectedURL.getAuthorities();
                    for (String protectedAuthority : protectedAuthorities) {
                        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(protectedAuthority);
                        authorities.add(grantedAuthority);
                    }
                }
            }
        }

        Collection<? extends GrantedAuthority> actualAuthorities = authentication.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            if (actualAuthorities.contains(authority)) {
                return ACCESS_GRANTED;
            }
        }

        return ACCESS_DENIED;
    }
}
